﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using FinPlusCommon;
using log = Logger.Logger;
using u = FinPlusUtility.Utility;

namespace FinPlusComponents
{
    public class FinPlusMarket: FinPlusComponent
    {
        public override string Id { get; set; }
        public override string[] States { get { return new string[] { }; } }
        public override string[] TestStates { get { return new string[] { "ModelTest", "IsValid" }; } }
        public override IFinPlusFunctions Model { get { return _instrumentConn.Model; } }
        public override string ModelTest { get { return Model.ToString(); } }
        public override bool IsValid { get; set; }

        private enum DockControls { FinPlusDataConn, FinPlusChildService, Deafult }
        private enum Connection { Instruments, MarketLevels, Throttle, Exception }
        private enum Params { LevelUpdate, Refresh, MarketUpdate, Level, BuySell, Shock, Instrument, Tag }

        private IFinPlusComponent _marketLevelConn, _instrumentConn, _throttleConn;
        private bool _hasInitialised;
        private readonly string _tag;

        //construct
        public FinPlusMarket(string tag)
        {
            _tag = tag;
        }

        //common control interface
        public override void Dock(object component, string dock)
        {
            try
            {
                switch (u.EnumTryParse<DockControls>(component.GetType().Name, DockControls.Deafult))
                {
                    case DockControls.FinPlusChildService:
                    case DockControls.FinPlusDataConn:
                    case DockControls.Deafult: AddConnection((IFinPlusComponent)component, dock); break;
                }
            }
            catch (Exception e)
            {
                IsValid = log.Log(Logger.Level.Error, Id, Config, e.Message, e);
            }
        }

        public override void Initialise()
        {
            if (_hasInitialised) return;

            _instrumentConn.Model.Get(Params.Shock.ToString(), new Function());
            _instrumentConn.Model.Get(Params.LevelUpdate.ToString(), new Function());
            _instrumentConn.Model.Get(Params.Refresh.ToString(), string.Empty, Level_Refresh);
            RefreshAll();
            IsValid = _hasInitialised = true;
        }

        public override void CommandRouter(IFinPlusFunction func)
        {
            try
            {
                CaptureCommand(func);

                switch ((Commands)Enum.Parse(typeof(Commands), func.Name, true))
                {
                    case Commands.Refresh: Refresh(func[Params.Tag.ToString()].ToString()); break;
                    default: throw new Exception(string.Format("event not recognised {0}", func.Name));
                }
            }
            catch (Exception e)
            {
                IsValid = log.Log(Logger.Level.Error, Id, Config, e.Message, e);
            }
        }

        public override void Dispose()
        {
            if (_instrumentConn != null)
                _instrumentConn.Dispose();

            if (_marketLevelConn != null)
                _marketLevelConn.Dispose();
        }

        //private
        private void Refresh(string instrumentName)
        {
            var instrument = _instrumentConn.Model.First(string.Format("Name='Instrument' And Value='{0}'", instrumentName));
            Refresh(instrument);
        }

        private void Refresh(IFinPlusFunction instrument)
        {
            if (instrument == null) 
                return;

            var marketLevels = _marketLevelConn.Model.Values.Where(f => f[Params.Instrument.ToString()].Equals(instrument[Params.Instrument.ToString()]));
            foreach (var marketLevel in marketLevels)
            {
                instrument.Get(Params.LevelUpdate.ToString()).Set(marketLevel);
                instrument.Get(string.Format("{0}{1}", _tag, marketLevel[Params.BuySell.ToString()].ToString()), 0.0).Set((double)marketLevel.Value(Params.Level.ToString()));
            }
        }

        private void RefreshAll()
        {
            foreach (var inst in _instrumentConn.Model.Values)
                Refresh(inst);
        }

        private void AddConnection(IFinPlusComponent conn, string dock)
        {
            switch (u.EnumTryParse<Connection>(dock, Connection.Exception))
            {
                case Connection.Instruments: _instrumentConn = conn; break;
                case Connection.MarketLevels: _marketLevelConn = conn; break;
                case Connection.Throttle: _marketLevelConn = conn; break;
                case Connection.Exception: throw new NotImplementedException();
            }
        }
       
        //cmds 
        private new enum Commands { Refresh }

        //events 
        private void Level_Refresh(object sender, PropertyChangedEventArgs a) 
        {
            CommandRouter(new Function(Commands.Refresh.ToString(), Id, User, -1, ((IFinPlusItem)sender).Value));
        }
    }
}
